home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / vmCOW.c < prev    next >
C/C++ Source or Header  |  1991-06-27  |  36KB  |  1,300 lines

  1. /* 
  2.  * vmCOW.c --
  3.  *
  4.  * This file contains routines that implement copy-on-write.
  5.  *
  6.  * Copy-on-write (COW) is implemented by linking all related instances of a
  7.  * segment in a list. "Related instances" means all segments related by a fork
  8.  * of some initial segment, including children, grandchildren, etc.  Each page
  9.  * in each related segment is marked either OK (meaning the page is no longer
  10.  * involved in any COW activity), COW or COR (meaning it's copy-on-reference).
  11.  * COR pages have no associated backing store or main-memory contents yet, but
  12.  * the PTE for each COR page names the segment from which this page is to be 
  13.  * copied by setting the page frame number equal to the segment number of the
  14.  * source of the page.  Pages are marked COW and COR through the use of the
  15.  * bits in the PTE.
  16.  *
  17.  * When a COR page is referenced, the routine VmCOR is called.  The source of
  18.  * the page is found through the page frame number and a copy of the page is 
  19.  * made.  The source is left COW.  When a COW page (call it A) is written then
  20.  * the routine VmCOW is called.  Another page (call it B) is found by
  21.  * traversing the list of segments.  Page A is then copied to page B and A is
  22.  * marked OK (no longer COW).  If there are any other pages that were COR off 
  23.  * of A besides B, then B is marked COW and each of the other pages is marked
  24.  * COR off of B.  Otherwise B is marked OK.
  25.  *
  26.  * During a fork the routine VmSegFork is called.  The newly created segment
  27.  * is added to the list of related segments which contains the new segment's
  28.  * parent.  For each page that is COR in the parent, the child is marked COR
  29.  * off of the same page.  For each page that is marked COW in the parent,
  30.  * the child is marked COR off of the parent.  For each parent page that is
  31.  * resident or on swap space, the child is marked COR off of the parent.
  32.  * All other pages (zero fill or demand load from the file system) are set up
  33.  * to be the same for the child.
  34.  *
  35.  * When a segment or a portion of a segment which contains COW pages is
  36.  * deleted then all of the COW pages must be duplicated.  This is done
  37.  * by calling the routine VmCOWDeleteFromSeg.  For each COW
  38.  * page (call it A), if there is segment which is COR off of A, then A is
  39.  * copied to B.  If A is resident this is done by remapping the page in A
  40.  * onto B.  Otherwise the swap space behind A is copied to B's backing store.
  41.  * 
  42.  * When a segment is migrated, a copy of it has to be made.  This is done by
  43.  * calling the routine VmCOWCopy.  For each COR page a COR fault is simulated.
  44.  * For each COW page a COW fault is simulated.
  45.  *
  46.  * SYNCHRONIZATION
  47.  *
  48.  * The routines in this file are designed to be called by routines in 
  49.  * vmPage.c and vmSeg.c.  Whenever any of these routines are called  it is
  50.  * assumed that the page tables for the segment have had their user count
  51.  * incremented so that it is safe to grab a pointer to the page tables outside.
  52.  * of the monitor lock. Also only one operation can occur to a
  53.  * copy-on-write chain at one time.  This is assured by embedding a lock into 
  54.  * a common data structure that all  segments in a copy-on-write chain 
  55.  * reference (VmCOWInfo).  Since only one operation can happen at a time and 
  56.  * the pages tables are safe this greatly simplifies the code.
  57.  *
  58.  * CLEANUP
  59.  *
  60.  * There are several cases in which the COW chain must be cleaned up.  The
  61.  * cases and how they are handled are:
  62.  *
  63.  * 1) After a COW or a COR fault occurs for page A, there may be no more pages
  64.  *    that are COR off of A.  However, there is no way of knowing this without
  65.  *    searching the entire chain.  In this case A is left COW and then if
  66.  *    a subsequent COW fault occurs on A, A will be marked OK.
  67.  * 2) After a COW or COR fault there may be no more COR or COW pages in the
  68.  *    faulting segment.  In this case the segment is deleted from the list.
  69.  * 3) After a COR fault, COW fault, or a segment is deleted there may be
  70.  *    only one segement left in the list.  In this case all pages are marked
  71.  *    OK in the segment, the segment is removed from the chain and the
  72.  *    VmCOWInfo struct is freed.
  73.  *
  74.  * Copyright (C) 1985 Regents of the University of California
  75.  * All rights reserved.
  76.  */
  77.  
  78. #ifndef lint
  79. static char rcsid[] = "$Header: /sprite/src/kernel/vm/RCS/vmCOW.c,v 9.6 91/06/27 17:41:50 mgbaker Exp $ SPRITE (Berkeley)";
  80. #endif not lint
  81.  
  82. #include <sprite.h>
  83. #include <vmStat.h>
  84. #include <vm.h>
  85. #include <vmInt.h>
  86. #include <vmTrace.h>
  87. #include <user/vm.h>
  88. #include <sync.h>
  89. #include <dbg.h>
  90. #include <list.h>
  91. #include <lock.h>
  92. #include <sys.h>
  93. #include <stdlib.h>
  94. #include <stdio.h>
  95. #include <bstring.h>
  96. #ifdef SOSP91
  97. #include <fsStat.h>
  98. #endif SOSP91
  99.  
  100. #ifdef sun4
  101. /*
  102.  * Due to the cache flushing necessitated by all the mapping games, COW
  103.  * seems to be a lose on the sun4 right now.
  104.  */
  105. Boolean    vm_CanCOW = FALSE;
  106. #else
  107. Boolean    vm_CanCOW = TRUE;
  108. #endif /* sun4 */
  109.  
  110. static void DoFork _ARGS_((register Vm_Segment *srcSegPtr,
  111.     register Vm_Segment *destSegPtr));
  112. static void GiveAwayPage _ARGS_((register Vm_Segment *srcSegPtr, int virtPage,
  113.     register Vm_PTE *srcPTEPtr, register Vm_Segment *destSegPtr,
  114.     Boolean others));
  115. static void ReleaseCOW  _ARGS_((Vm_PTE *ptePtr));
  116. static Boolean COWStart _ARGS_((register Vm_Segment *segPtr,
  117.     register VmCOWInfo **cowInfoPtrPtr));
  118. static Vm_Segment *FindNewMasterSeg _ARGS_((register Vm_Segment *segPtr,
  119.     int page, Boolean *othersPtr));
  120. static Boolean IsResident _ARGS_((Vm_PTE *ptePtr));
  121. static void COWEnd _ARGS_((register Vm_Segment *segPtr,
  122.     VmCOWInfo **cowInfoPtrPtr));
  123. static void SetPTE _ARGS_((Vm_VirtAddr *virtAddrPtr, Vm_PTE pte));
  124. static void CopyPage _ARGS_((unsigned int srcPF, unsigned int destPF));
  125. static ReturnStatus COR _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  126.     register Vm_PTE *ptePtr));
  127. static void COW _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  128.     register Vm_PTE *ptePtr, Boolean isResident, Boolean deletePage));
  129. static unsigned int GetMasterPF();
  130. static void SeeIfLastCOR _ARGS_((register Vm_Segment *mastSegPtr,
  131.     int page));
  132.  
  133.  
  134. /*
  135.  *----------------------------------------------------------------------
  136.  *
  137.  * VmSegFork --
  138.  *
  139.  *    Make a copy-on-reference copy of the given segment.  It is assumed
  140.  *    that this routine is called with the source segment's page table
  141.  *    in use count incremented.
  142.  *
  143.  * Results:
  144.  *    None.
  145.  *
  146.  * Side effects:
  147.  *    Memory may be allocated for COW info struct.
  148.  *
  149.  *----------------------------------------------------------------------
  150.  */
  151. void
  152. VmSegFork(srcSegPtr, destSegPtr)
  153.     Vm_Segment    *srcSegPtr;
  154.     Vm_Segment    *destSegPtr;
  155. {
  156.     VmCOWInfo    *cowInfoPtr;
  157.  
  158.     cowInfoPtr = (VmCOWInfo *)malloc(sizeof(VmCOWInfo));
  159.     (void)COWStart(srcSegPtr, &cowInfoPtr);
  160.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  161.     free((Address)cowInfoPtr);
  162.     }
  163.     DoFork(srcSegPtr, destSegPtr);
  164. }
  165.  
  166.  
  167. /*
  168.  *----------------------------------------------------------------------
  169.  *
  170.  * DoFork --
  171.  *
  172.  *    Make the dest segment copy-on-reference off of the src segment.
  173.  *
  174.  * Results:
  175.  *    None.
  176.  *
  177.  * Side effects:
  178.  *    Source and destination page tables modified to set up things
  179.  *    as copy-on-write and copy-on-reference.  Also number of COW and COR
  180.  *    pages in each segment is modified.
  181.  *
  182.  *----------------------------------------------------------------------
  183.  */
  184. static void
  185. DoFork(srcSegPtr, destSegPtr)
  186.     register    Vm_Segment    *srcSegPtr;
  187.     register    Vm_Segment    *destSegPtr;
  188. {    
  189.     register    Vm_PTE    *destPTEPtr;
  190.     register    Vm_PTE    *srcPTEPtr;
  191.     register    int    virtPage;
  192.     register    int    lastPage;
  193.     register    int    numCORPages = 0;
  194.     register    int    numCOWPages = 0;
  195.     register    Vm_PTE    corPTE;
  196.     Vm_VirtAddr        virtAddr;
  197.     VmCOWInfo        *cowInfoPtr;
  198.  
  199.     LOCK_MONITOR;
  200.  
  201.     corPTE = VM_VIRT_RES_BIT | VM_COR_BIT | srcSegPtr->segNum;
  202.  
  203.     if (srcSegPtr->type == VM_HEAP) {
  204.     virtPage = srcSegPtr->offset;
  205.     lastPage = virtPage + srcSegPtr->numPages - 1;
  206.     srcPTEPtr = srcSegPtr->ptPtr;
  207.     destPTEPtr = destSegPtr->ptPtr;
  208.     } else {
  209.     virtPage = mach_LastUserStackPage - srcSegPtr->numPages + 1;
  210.     lastPage = mach_LastUserStackPage;
  211.     srcPTEPtr = VmGetPTEPtr(srcSegPtr, virtPage);
  212.     destPTEPtr = VmGetPTEPtr(destSegPtr, virtPage);
  213.     }
  214.  
  215.     virtAddr.segPtr = srcSegPtr;
  216.     virtAddr.flags = 0;
  217.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  218.     for (; virtPage <= lastPage;
  219.      virtPage++, VmIncPTEPtr(srcPTEPtr, 1), VmIncPTEPtr(destPTEPtr, 1)) {
  220.     if (!(*srcPTEPtr & VM_VIRT_RES_BIT)) {
  221.         *destPTEPtr = 0;
  222.         continue;
  223.     }
  224.     while (*srcPTEPtr & VM_IN_PROGRESS_BIT) {
  225.         (void)Sync_Wait(&srcSegPtr->condition, FALSE);
  226.     }
  227.     if (*srcPTEPtr & VM_COW_BIT) {
  228.         /*
  229.          * This page is already copy-on-write.  Make child copy-on-ref
  230.          * off of the parent segment.
  231.          */
  232.         *destPTEPtr = corPTE;
  233.         numCORPages++;
  234.     } else if (*srcPTEPtr & VM_COR_BIT) {
  235.         /*
  236.          * This page is already copy-on-reference.  Make the child be
  237.          * copy-on-ref on the same segment.
  238.          */
  239.         *destPTEPtr = *srcPTEPtr;
  240.         numCORPages++;
  241.     } else if (*srcPTEPtr & (VM_PHYS_RES_BIT | VM_ON_SWAP_BIT)) {
  242.         /*
  243.          * Need to make the src copy-on-write and the dest copy-on-ref.
  244.          */
  245.         *srcPTEPtr |= VM_COW_BIT;
  246.         if (*srcPTEPtr & VM_PHYS_RES_BIT) {
  247.         virtAddr.page = virtPage;
  248.         virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  249.         VmMach_SetPageProt(&virtAddr, *srcPTEPtr);
  250.         }
  251.         numCOWPages++;
  252.         *destPTEPtr = corPTE;
  253.         numCORPages++;
  254.     } else {
  255.         /*
  256.          * Just a normal everyday pte (zerofill or load from FS).
  257.          */
  258.         *destPTEPtr = *srcPTEPtr;
  259.     }
  260.     }
  261.  
  262.     cowInfoPtr = srcSegPtr->cowInfoPtr;
  263.     if (numCORPages > 0) {
  264.     if (srcSegPtr->type == VM_HEAP) {
  265.         vmStat.numCOWHeapPages += numCOWPages;
  266.         vmStat.numCORHeapPages += numCORPages;
  267.     } else {
  268.         vmStat.numCOWStkPages += numCOWPages;
  269.         vmStat.numCORStkPages += numCORPages;
  270.     }
  271.     srcSegPtr->numCOWPages += numCOWPages;
  272.     destSegPtr->numCORPages = numCORPages;
  273.     /*
  274.      * Insert the child into the COW list for the parent segment.
  275.      */
  276.     destSegPtr->cowInfoPtr = cowInfoPtr;
  277.     List_Insert((List_Links *)destSegPtr, 
  278.             LIST_ATREAR(&cowInfoPtr->cowList));
  279.     cowInfoPtr->numSegs++;
  280.     }
  281.     cowInfoPtr->copyInProgress = 0;
  282.     Sync_Broadcast(&cowInfoPtr->condition);
  283.  
  284.     UNLOCK_MONITOR;
  285. }
  286.  
  287.  
  288. /*
  289.  *----------------------------------------------------------------------
  290.  *
  291.  * VmCOWCopySeg --
  292.  *
  293.  *    Make a copy of the given segment.  This includes handling all
  294.  *    copy-on-write and copy-on-reference pages.  This segment will
  295.  *    be removed from its copy-on-write chain.  It is assumed that the
  296.  *    calling segment has the in-use count of its page tables incremented.
  297.  *
  298.  * Results:
  299.  *    None.
  300.  *
  301.  * Side effects:
  302.  *    Memory for a COW info struct may be freed.
  303.  *
  304.  *----------------------------------------------------------------------
  305.  */
  306. ReturnStatus
  307. VmCOWCopySeg(segPtr)
  308.     register    Vm_Segment    *segPtr;
  309. {
  310.     register    Vm_PTE        *ptePtr;
  311.     VmCOWInfo            *cowInfoPtr;
  312.     Vm_VirtAddr            virtAddr;
  313.     int                firstPage;
  314.     int                lastPage;
  315.     ReturnStatus        status = SUCCESS;
  316.  
  317.     cowInfoPtr = (VmCOWInfo *)NIL;
  318.     if (!COWStart(segPtr, &cowInfoPtr)) {
  319.     return(SUCCESS);
  320.     }
  321.     if (segPtr->type == VM_STACK) {
  322.     firstPage = mach_LastUserStackPage - segPtr->numPages + 1;
  323.     } else {
  324.     firstPage = segPtr->offset;
  325.     }
  326.     lastPage = firstPage + segPtr->numPages - 1;
  327.     virtAddr.segPtr = segPtr;
  328.     virtAddr.flags = 0;
  329.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  330.     for (virtAddr.page = firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  331.      virtAddr.page <= lastPage;
  332.      virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  333.     if (*ptePtr & VM_COW_BIT) {
  334.         COW(&virtAddr, ptePtr, IsResident(ptePtr), FALSE);
  335.         VmPageValidate(&virtAddr);
  336.     } else if (*ptePtr & VM_COR_BIT) {
  337.         status = COR(&virtAddr, ptePtr);
  338.         if (status != SUCCESS) {
  339.         break;
  340.         }
  341.     }
  342.     }
  343.  
  344.     cowInfoPtr = (VmCOWInfo *)NIL;
  345.     COWEnd(segPtr, &cowInfoPtr);
  346.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  347.     free((Address)cowInfoPtr);
  348.     }
  349.     return(status);
  350. }
  351.  
  352.  
  353. /*
  354.  *----------------------------------------------------------------------
  355.  *
  356.  * VmCOWDeleteFromSeg --
  357.  *
  358.  *    Invalidate all cow or cor pages from the given range of pages in
  359.  *    the given segment.  It is assumed that this routine is called with
  360.  *    the segment's page tables in use count incremented.
  361.  *
  362.  * Results:
  363.  *    None.
  364.  *
  365.  * Side effects:
  366.  *    All cow or cor pages in the given range of pages are invalidated.
  367.  *
  368.  *----------------------------------------------------------------------
  369.  */
  370. void
  371. VmCOWDeleteFromSeg(segPtr, firstPage, lastPage)
  372.     register    Vm_Segment    *segPtr;
  373.     register    int        firstPage;    /* First page to delete. -1
  374.                          * if want the lowest possible
  375.                          * page. */
  376.     register    int        lastPage;    /* Last page to delete. -1
  377.                          * if want the highest possible
  378.                          * page. */
  379. {
  380.     register    Vm_PTE        *ptePtr;
  381.     VmCOWInfo            *cowInfoPtr;
  382.     Vm_VirtAddr            virtAddr;
  383.  
  384.     if (firstPage == -1) {
  385.     /*
  386.      * Caller wants to invalidate all pages for this segment.  This
  387.      * is only done when the segment is deleted.
  388.      */
  389.     if (segPtr->type == VM_STACK) {
  390.         firstPage = mach_LastUserStackPage - segPtr->numPages + 1;
  391.     } else {
  392.         firstPage = segPtr->offset;
  393.     }
  394.     lastPage = firstPage + segPtr->numPages - 1;
  395.     }
  396.     cowInfoPtr = (VmCOWInfo *)NIL;
  397.     if (!COWStart(segPtr, &cowInfoPtr)) {
  398.     return;
  399.     }
  400.     virtAddr.segPtr = segPtr;
  401.     virtAddr.flags = 0;
  402.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  403.     for (ptePtr = VmGetPTEPtr(segPtr, firstPage);
  404.      firstPage <= lastPage;
  405.      firstPage++, VmIncPTEPtr(ptePtr, 1)) {
  406.     if (*ptePtr & VM_COW_BIT) {
  407.         virtAddr.page = firstPage;
  408.         COW(&virtAddr, ptePtr, IsResident(ptePtr), TRUE);
  409.     } else if (*ptePtr & VM_COR_BIT) {
  410.         segPtr->numCORPages--;
  411.         if (segPtr->numCORPages < 0) {
  412.         panic("VmCOWDeleteFromSeg: numCORPages < 0\n");
  413.         }
  414.     }
  415.     }
  416.  
  417.     cowInfoPtr = (VmCOWInfo *)NIL;
  418.     COWEnd(segPtr, &cowInfoPtr);
  419.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  420.     free((Address)cowInfoPtr);
  421.     }
  422. }
  423.  
  424.  
  425. /*
  426.  *----------------------------------------------------------------------
  427.  *
  428.  * COWStart --
  429.  *
  430.  *    Mark the segment as copy-on-write in progress.  After this routine
  431.  *    is called all future copy-on-writes are blocked until released
  432.  *    by a call to COWEnd.
  433.  *
  434.  * Results:
  435.  *    If the segment is not currently involved in a copy-on-write chain and
  436.  *    *cowInfoPtrPtr is NIL then this routine returns FALSE.  Otherwise
  437.  *    it returns TRUE.
  438.  *
  439.  * Side effects:
  440.  *    Copy-in-progress flag is set.  Also if there is no copy-on-write
  441.  *    chain yet and *cowInfoPtrPtr is not equal to NIL, then a new
  442.  *    one is created and *cowInfoPtrPtr is set to NIL.
  443.  *
  444.  *----------------------------------------------------------------------
  445.  */
  446. static Boolean
  447. COWStart(segPtr, cowInfoPtrPtr)
  448.     register    Vm_Segment    *segPtr;    /* Segment to begin COW for.*/
  449.     register    VmCOWInfo    **cowInfoPtrPtr;/* Pointer to pointer to
  450.                          * COW info struct that can
  451.                          * be used if no struct yet
  452.                          * exists. */ 
  453. {
  454.     register    VmCOWInfo    *cowInfoPtr;
  455.  
  456.     LOCK_MONITOR;
  457.  
  458. again:
  459.  
  460.     if (segPtr->cowInfoPtr == (VmCOWInfo *)NIL) {
  461.     cowInfoPtr = *cowInfoPtrPtr;
  462.     if (cowInfoPtr == (VmCOWInfo *)NIL) {
  463.         UNLOCK_MONITOR;
  464.         return(FALSE);
  465.     }
  466.     segPtr->cowInfoPtr = cowInfoPtr;
  467.     cowInfoPtr->copyInProgress = TRUE;
  468.     List_Init(&cowInfoPtr->cowList);
  469.     List_Insert((List_Links *)segPtr, LIST_ATREAR(&cowInfoPtr->cowList));
  470.     cowInfoPtr->numSegs = 1;
  471.     *cowInfoPtrPtr = (VmCOWInfo *)NIL;
  472.     } else {
  473.     cowInfoPtr = segPtr->cowInfoPtr;
  474.     if (cowInfoPtr->copyInProgress) {
  475.         (void)Sync_Wait(&cowInfoPtr->condition, FALSE);
  476.         goto again;
  477.     } else {
  478.         cowInfoPtr->copyInProgress = TRUE;
  479.     }
  480.     }
  481.  
  482.     UNLOCK_MONITOR;
  483.     return(TRUE);
  484. }
  485.  
  486.  
  487. /*
  488.  *----------------------------------------------------------------------
  489.  *
  490.  * COWEnd --
  491.  *
  492.  *    Clean up after a copy-on-write or copy-on-ref has happened.
  493.  *
  494.  * Results:
  495.  *    None.
  496.  *
  497.  * Side effects:
  498.  *    *cowInfoPtrPtr is set to point to COW info struct to free if there
  499.  *    are no segments left COW.
  500.  *
  501.  *----------------------------------------------------------------------
  502.  */
  503. static void
  504. COWEnd(segPtr, cowInfoPtrPtr)
  505.     register    Vm_Segment    *segPtr;     /* Segment that was involved
  506.                           * in the COW or COR. */
  507.     VmCOWInfo            **cowInfoPtrPtr; /* Set to point to a COW
  508.                           * info struct to free. */
  509. {
  510.     register    VmCOWInfo    *cowInfoPtr;
  511.  
  512.  
  513.     LOCK_MONITOR;
  514.  
  515.     cowInfoPtr = segPtr->cowInfoPtr;
  516.     cowInfoPtr->copyInProgress = FALSE;
  517.     Sync_Broadcast(&cowInfoPtr->condition);
  518.     if (segPtr->numCOWPages == 0 && segPtr->numCORPages == 0) {
  519.     List_Remove((List_Links *)segPtr);
  520.     segPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  521.     cowInfoPtr->numSegs--;
  522.     }
  523.     if (cowInfoPtr->numSegs == 0) {
  524.     *cowInfoPtrPtr = cowInfoPtr;
  525.     } else if (cowInfoPtr->numSegs == 1) {
  526.     register Vm_Segment    *cowSegPtr;
  527.     register Vm_PTE        *ptePtr;
  528.     int            firstPage;
  529.     int            lastPage;
  530.     register int        i;
  531.     /*
  532.      * Only one segment left.  Return this segment back to normal
  533.      * protection and clean up.
  534.      */
  535.     *cowInfoPtrPtr = cowInfoPtr;
  536.     cowSegPtr = (Vm_Segment *)List_First(&cowInfoPtr->cowList);
  537.     if (vm_Tracing) {
  538.         Vm_TraceClearCOW    clearCOW;
  539.  
  540.         clearCOW.segNum = cowSegPtr->segNum;
  541.         VmStoreTraceRec(VM_TRACE_CLEAR_COW_REC, sizeof(clearCOW),
  542.                 (Address)&clearCOW, TRUE);
  543.     }
  544.     cowSegPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  545.     if (cowSegPtr->type == VM_STACK) {
  546.         firstPage = mach_LastUserStackPage - cowSegPtr->numPages + 1;
  547.     } else {
  548.         firstPage = cowSegPtr->offset;
  549.     }
  550.     lastPage = firstPage + cowSegPtr->numPages - 1;
  551.     for (ptePtr = VmGetPTEPtr(cowSegPtr, firstPage),
  552.         i = cowSegPtr->numPages;
  553.          i > 0;
  554.          i--, VmIncPTEPtr(ptePtr, 1)) {
  555.         *ptePtr &= ~(VM_COW_BIT | VM_COR_BIT);
  556.     }
  557.     VmMach_SetSegProt(cowSegPtr, firstPage, lastPage, TRUE);
  558.     cowSegPtr->numCORPages = 0;
  559.     cowSegPtr->numCOWPages = 0;
  560.     }
  561.  
  562.     UNLOCK_MONITOR;
  563. }
  564.  
  565.  
  566. /*
  567.  *----------------------------------------------------------------------
  568.  *
  569.  * FindNewMasterSeg --
  570.  *
  571.  *    Find a segment that is sharing the given page copy-on-reference.
  572.  *
  573.  * Results:
  574.  *    Pointer to segment that is sharing the given page copy-on-reference.
  575.  *
  576.  * Side effects:
  577.  *    All segments that are now dependent on the new master have their page
  578.  *    table entries set to point to the new master segment.
  579.  *
  580.  *----------------------------------------------------------------------
  581.  */
  582. static Vm_Segment *
  583. FindNewMasterSeg(segPtr, page, othersPtr)
  584.     register    Vm_Segment    *segPtr;    /* Current master. */
  585.     int                page;        /* Virtual page. */
  586.     Boolean            *othersPtr;    /* Set to TRUE if there are
  587.                          * other COW children. */
  588. {
  589.     register    List_Links    *cowList;
  590.     register    Vm_Segment    *newSegPtr;
  591.     register    Vm_PTE        *ptePtr;
  592.     Vm_Segment            *mastSegPtr = (Vm_Segment *)NIL;
  593.  
  594.     *othersPtr = FALSE;
  595.     cowList = &segPtr->cowInfoPtr->cowList;
  596.     newSegPtr = (Vm_Segment *)List_Next((List_Links  *)segPtr);
  597.     while (!List_IsAtEnd(cowList, (List_Links *)newSegPtr)) {
  598.     /*
  599.      * Make sure the page exists in this segment, then check the PTE.
  600.      */
  601.     if (page - newSegPtr->offset < newSegPtr->ptSize) {
  602.         ptePtr = VmGetPTEPtr(newSegPtr, page);
  603.         if ((*ptePtr & VM_COR_BIT) &&
  604.         Vm_GetPageFrame(*ptePtr) == segPtr->segNum) {
  605.         if (mastSegPtr != (Vm_Segment *)NIL) {
  606.             *ptePtr &= ~VM_PAGE_FRAME_FIELD;
  607.             *ptePtr |= mastSegPtr->segNum;
  608.             *othersPtr = TRUE;
  609.         } else {
  610.             mastSegPtr = newSegPtr;
  611.         }
  612.         }
  613.     }
  614.     newSegPtr = (Vm_Segment *)List_Next((List_Links  *)newSegPtr);
  615.     }
  616.     return(mastSegPtr);
  617. }
  618.  
  619.  
  620. /*
  621.  *----------------------------------------------------------------------
  622.  *
  623.  * IsResident --
  624.  *
  625.  *    Determine if the page is resident in the given page table entry.
  626.  *
  627.  * Results:
  628.  *    TRUE if the page is resident. 
  629.  *
  630.  * Side effects:
  631.  *    Page locked down if resident.
  632.  *
  633.  *----------------------------------------------------------------------
  634.  */
  635. static Boolean
  636. IsResident(ptePtr)
  637.     Vm_PTE    *ptePtr;
  638. {
  639.     Boolean    retVal;
  640.  
  641.     LOCK_MONITOR;
  642.  
  643.     if (*ptePtr & VM_PHYS_RES_BIT) {
  644.     VmLockPageInt(Vm_GetPageFrame(*ptePtr));
  645.     retVal = TRUE;
  646.     } else {
  647.     retVal = FALSE;
  648.     }
  649.  
  650.     UNLOCK_MONITOR;
  651.  
  652.     return(retVal);
  653. }
  654.  
  655.  
  656. /*
  657.  *----------------------------------------------------------------------
  658.  *
  659.  * VmCOR --
  660.  *
  661.  *    Handle a copy-on-reference fault.  If the virtual address is not
  662.  *    truly COR then don't do anything.  It is assumed that the given
  663.  *    segment's page tables have had their in-use count incremented.
  664.  *
  665.  * Results:
  666.  *    Status from VmPageServerRead if had to read from swap space.  
  667.  *    Otherwise SUCCESS.
  668.  *
  669.  * Side effects:
  670.  *    Page table for current segment is modified.
  671.  *
  672.  *----------------------------------------------------------------------
  673.  */
  674. ReturnStatus
  675. VmCOR(virtAddrPtr)
  676.     register    Vm_VirtAddr    *virtAddrPtr;
  677. {
  678.     register    Vm_PTE        *ptePtr;
  679.     VmCOWInfo            *cowInfoPtr;
  680.     ReturnStatus        status;
  681.  
  682.     if (virtAddrPtr->segPtr->type == VM_HEAP) {
  683.     vmStat.numCORHeapFaults++;
  684.     } else {
  685.     vmStat.numCORStkFaults++;
  686.     }
  687.     cowInfoPtr = (VmCOWInfo *)NIL;
  688.     if (!COWStart(virtAddrPtr->segPtr, &cowInfoPtr)) {
  689.     vmStat.quickCORFaults++;
  690.     return(SUCCESS);
  691.     }
  692.     ptePtr = VmGetAddrPTEPtr(virtAddrPtr, virtAddrPtr->page);
  693.     if (!(*ptePtr & VM_COR_BIT)) {
  694.     vmStat.quickCORFaults++;
  695.     status = SUCCESS;
  696.     } else {
  697.     status = COR(virtAddrPtr, ptePtr);
  698.     }
  699.  
  700.     cowInfoPtr = (VmCOWInfo *)NIL;
  701.     COWEnd(virtAddrPtr->segPtr, &cowInfoPtr);
  702.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  703.     free((Address)cowInfoPtr);
  704.     }
  705.  
  706.     return(status);
  707. }
  708.  
  709.  
  710. /*
  711.  *----------------------------------------------------------------------
  712.  *
  713.  * COR --
  714.  *
  715.  *    Handle a copy-on-reference fault.
  716.  *
  717.  * Results:
  718.  *    Status from VmPageServerRead if had to read from swap space.  
  719.  *    Otherwise SUCCESS.
  720.  *
  721.  * Side effects:
  722.  *    Page table for current segment is modified.
  723.  *
  724.  *----------------------------------------------------------------------
  725.  */
  726. static ReturnStatus
  727. COR(virtAddrPtr, ptePtr)
  728.     register    Vm_VirtAddr    *virtAddrPtr;
  729.     register    Vm_PTE        *ptePtr;
  730. {
  731.     register    Vm_Segment    *mastSegPtr;
  732.     unsigned    int        virtFrameNum;
  733.     unsigned    int        mastVirtPF;
  734.     ReturnStatus        status;
  735.     int                corCheckBit;
  736.  
  737.     mastSegPtr = VmGetSegPtr((int) (Vm_GetPageFrame(*ptePtr)));
  738.     virtFrameNum = VmPageAllocate(virtAddrPtr, VM_CAN_BLOCK);
  739.     mastVirtPF = GetMasterPF(mastSegPtr, virtAddrPtr->page);
  740.     if (mastVirtPF != 0) {
  741.     /*
  742.      * The page is resident in memory so copy it.
  743.      */
  744.     CopyPage(mastVirtPF, virtFrameNum);
  745.     VmUnlockPage(mastVirtPF);
  746.     } else {
  747. #ifdef SOSP91
  748.     Boolean    isForeign = FALSE;
  749. #endif SOSP91
  750.     /*
  751.      * Load the page off of swap space.
  752.      */
  753.     Vm_VirtAddr    virtAddr;
  754.  
  755.     virtAddr.segPtr = mastSegPtr;
  756.     virtAddr.page = virtAddrPtr->page;
  757.     virtAddr.flags = 0;
  758.     virtAddr.sharedPtr = virtAddrPtr->sharedPtr;
  759.     status = VmPageServerRead(&virtAddr, virtFrameNum);
  760. #ifdef SOSP91
  761.     fs_MoreStats.CORPageServerRead++;
  762.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  763.         if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  764.             (proc_RunningProcesses[0]->genFlags &
  765.             (PROC_FOREIGN | PROC_MIGRATING))) {
  766.         isForeign = TRUE;
  767.         }
  768.     }
  769.     if (isForeign) {
  770.         fs_MoreStats.CORPageServerReadM++;
  771.     }
  772. #endif SOSP91
  773.     if (status != SUCCESS) {
  774.         printf("Warning: VmCOR: Couldn't read page, status <%x>\n", status);
  775.         VmPageFree(virtFrameNum);
  776.         return(status);
  777.     }
  778.     }
  779.  
  780.     virtAddrPtr->segPtr->numCORPages--;
  781.     if (virtAddrPtr->segPtr->numCORPages < 0) {
  782.     panic("COR: numCORPages < 0\n");
  783.     }
  784.     if (vmCORReadOnly) {
  785.     corCheckBit = VM_COR_CHECK_BIT | VM_READ_ONLY_PROT;
  786.     } else {
  787.     corCheckBit = 0;
  788.     }
  789.  
  790.     SetPTE(virtAddrPtr, (Vm_PTE)(VM_VIRT_RES_BIT | VM_PHYS_RES_BIT | 
  791.              VM_REFERENCED_BIT | VM_MODIFIED_BIT | corCheckBit |
  792.              virtFrameNum));
  793.     VmUnlockPage(virtFrameNum);
  794.     SeeIfLastCOR(mastSegPtr, virtAddrPtr->page);
  795.     return(SUCCESS);
  796. }
  797.  
  798.  
  799. /*
  800.  *----------------------------------------------------------------------
  801.  *
  802.  * GetMasterPF --
  803.  *
  804.  *    Return the page frame from the master segment's page table
  805.  *    entry.  0 if the page is not resident.
  806.  *
  807.  * Results:
  808.  *    The page frame from the masters PTE.  0 if not resident.
  809.  *    Otherwise SUCCESS.
  810.  *
  811.  * Side effects:
  812.  *    Page frame returned locked if resident.
  813.  *
  814.  *----------------------------------------------------------------------
  815.  */
  816. static unsigned int
  817. GetMasterPF(mastSegPtr, virtPage)
  818.     Vm_Segment    *mastSegPtr;
  819.     int        virtPage;
  820. {
  821.     unsigned    int    pf;
  822.     register    Vm_PTE    *mastPTEPtr;
  823.  
  824.     LOCK_MONITOR;
  825.  
  826.     mastPTEPtr = VmGetPTEPtr(mastSegPtr, virtPage);
  827.     if (*mastPTEPtr & VM_PHYS_RES_BIT) {
  828.     pf = Vm_GetPageFrame(*mastPTEPtr);
  829.     VmLockPageInt(pf);
  830.     } else {
  831.     pf = 0;
  832.     }
  833.  
  834.     UNLOCK_MONITOR;
  835.  
  836.     return(pf);
  837. }
  838.  
  839.  
  840. /*
  841.  *----------------------------------------------------------------------
  842.  *
  843.  * SeeIfLastCOR --
  844.  *
  845.  *    See if there are any more segments that are COR off of the given 
  846.  *    page in the given segment.
  847.  *
  848.  * Results:
  849.  *    None.
  850.  *
  851.  * Side effects:
  852.  *    If there are no other pages COR of the given page in the given segment
  853.  *    then the page is made no longer COW.
  854.  *
  855.  *----------------------------------------------------------------------
  856.  */
  857. static void
  858. SeeIfLastCOR(mastSegPtr, page)
  859.     register    Vm_Segment    *mastSegPtr;
  860.     int                page;
  861. {
  862.     register    List_Links    *cowList;
  863.     register    Vm_Segment    *childSegPtr;
  864.     register    Vm_PTE        *ptePtr;
  865.     Vm_VirtAddr            virtAddr;
  866.  
  867.     LOCK_MONITOR;
  868.  
  869.     cowList = &mastSegPtr->cowInfoPtr->cowList;
  870.     childSegPtr = (Vm_Segment *)List_Next((List_Links *)mastSegPtr);
  871.     while (!List_IsAtEnd(cowList, (List_Links *)childSegPtr)) {
  872.     /*
  873.      * Make sure the page exists in this segment, then check the PTE.
  874.      */
  875.     if (page - childSegPtr->offset < childSegPtr->ptSize) {
  876.         ptePtr = VmGetPTEPtr(childSegPtr, page);
  877.         if ((*ptePtr & VM_COR_BIT) &&
  878.         Vm_GetPageFrame(*ptePtr) == mastSegPtr->segNum) {
  879.         UNLOCK_MONITOR;
  880.         return;
  881.         }
  882.     }
  883.     childSegPtr = (Vm_Segment *)List_Next((List_Links *)childSegPtr);
  884.     }
  885.  
  886.     /*
  887.      * No more pages are COR off of the master.  Make the page no longer
  888.      * copy-on-write.
  889.      */
  890.     ptePtr = VmGetPTEPtr(mastSegPtr, page);
  891.     if (vm_Tracing) {
  892.     Vm_TracePTEChange    pteChange;
  893.  
  894.     pteChange.changeType = VM_TRACE_LAST_COR;
  895.     pteChange.softPTE = TRUE;
  896.     pteChange.segNum = mastSegPtr->segNum;
  897.     pteChange.pageNum = page;
  898.     pteChange.beforePTE = *ptePtr;
  899.     pteChange.afterPTE = *ptePtr & ~VM_COW_BIT;
  900.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC, sizeof(pteChange),
  901.             (Address)&pteChange, TRUE);
  902.     }
  903.     *ptePtr &= ~VM_COW_BIT;
  904.     mastSegPtr->numCOWPages--;
  905.     if (mastSegPtr->numCOWPages == 0 && mastSegPtr->numCORPages == 0) {
  906.     /*
  907.      * If there are no more COW or COR pages then remove ourselves
  908.      * from the list.  We know that we are only called by the routine
  909.      * COR() which means that there is guaranteed to be at least one
  910.      * segment left in the list.  Therefore there is no need to worry
  911.      * about freeing up the cow info struct.
  912.      */
  913.     List_Remove((List_Links *)mastSegPtr);
  914.     mastSegPtr->cowInfoPtr->numSegs--;
  915.     mastSegPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  916.     }
  917.     if (*ptePtr & VM_PHYS_RES_BIT) {
  918.     virtAddr.segPtr = mastSegPtr;
  919.     virtAddr.page = page;
  920.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  921.     VmMach_SetPageProt(&virtAddr, *ptePtr);
  922.     }
  923.  
  924.     UNLOCK_MONITOR;
  925. }
  926.  
  927.  
  928. /*
  929.  *----------------------------------------------------------------------
  930.  *
  931.  * VmCOW --
  932.  *
  933.  *    Handle a copy-on-write fault.  If the current virtual address is
  934.  *    not truly COW then we don't do anything.
  935.  *
  936.  * Results:
  937.  *    None.
  938.  *
  939.  * Side effects:
  940.  *    Page table for the given virtual address is modified and the page
  941.  *    table of the new master (if any) is modified.
  942.  *
  943.  *----------------------------------------------------------------------
  944.  */
  945. void
  946. VmCOW(virtAddrPtr)
  947.     register    Vm_VirtAddr    *virtAddrPtr;
  948. {
  949.     register    Vm_PTE        *ptePtr;
  950.     VmCOWInfo            *cowInfoPtr;
  951.  
  952.     if (virtAddrPtr->segPtr->type == VM_HEAP) {
  953.     vmStat.numCOWHeapFaults++;
  954.     } else {
  955.     vmStat.numCOWStkFaults++;
  956.     }
  957.     cowInfoPtr = (VmCOWInfo *)NIL;
  958.     if (!COWStart(virtAddrPtr->segPtr, &cowInfoPtr)) {
  959.     vmStat.quickCOWFaults++;
  960.     return;
  961.     }
  962.     ptePtr = VmGetAddrPTEPtr(virtAddrPtr, virtAddrPtr->page);
  963.     if (!(*ptePtr & VM_COW_BIT)) {
  964.     vmStat.quickCOWFaults++;
  965.     } else if (IsResident(ptePtr)) {
  966.     COW(virtAddrPtr, ptePtr, TRUE, FALSE);
  967.     }
  968.  
  969.     cowInfoPtr = (VmCOWInfo *)NIL;
  970.     COWEnd(virtAddrPtr->segPtr, &cowInfoPtr);
  971.     if (cowInfoPtr != (VmCOWInfo *)NIL) {
  972.     free((Address)cowInfoPtr);
  973.     }
  974. }
  975.  
  976.  
  977. /*
  978.  *----------------------------------------------------------------------
  979.  *
  980.  * COW --
  981.  *
  982.  *    Handle a copy-on-write fault.
  983.  *
  984.  * Results:
  985.  *    None.
  986.  *
  987.  * Side effects:
  988.  *    None.
  989.  *
  990.  *----------------------------------------------------------------------
  991.  */
  992. static void
  993. COW(virtAddrPtr, ptePtr, isResident, deletePage)
  994.     register    Vm_VirtAddr    *virtAddrPtr;    /* Virtual address to copy.*/
  995.     register    Vm_PTE        *ptePtr;    /* Pointer to the page table
  996.                          * entry. */
  997.     Boolean            isResident;    /* TRUE => The page is resident
  998.                          *       in memory and locked
  999.                          *       down. */
  1000.     Boolean            deletePage;    /* TRUE => Delete the page
  1001.                          *         after copying. */
  1002. {
  1003.     register    Vm_Segment    *mastSegPtr;
  1004.     Vm_VirtAddr            virtAddr;
  1005.     Boolean            others;
  1006.     unsigned int        virtFrameNum;
  1007.     Vm_PTE            pte;
  1008. #ifdef SOSP91
  1009.     Boolean    isForeign = FALSE;
  1010. #endif SOSP91
  1011.  
  1012.     mastSegPtr = FindNewMasterSeg(virtAddrPtr->segPtr, virtAddrPtr->page,
  1013.                   &others);
  1014.     if (mastSegPtr != (Vm_Segment *)NIL) {
  1015.     mastSegPtr->numCORPages--;
  1016.     if (mastSegPtr->numCORPages < 0) {
  1017.         panic("COW: numCORPages < 0\n");
  1018.     }
  1019.     if (others) {
  1020.         mastSegPtr->numCOWPages++;
  1021.     }
  1022.     virtAddr.segPtr = mastSegPtr;
  1023.     virtAddr.page = virtAddrPtr->page;
  1024.     virtAddr.flags = 0;
  1025.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  1026.     if (isResident) {
  1027.         /*
  1028.          * The page is resident and locked down by our caller. 
  1029.          */
  1030.         if (deletePage) {
  1031.         /*
  1032.          * This page is being invalidated. In this case just give
  1033.          * away the page, no need to copy it.
  1034.          */
  1035.         GiveAwayPage(virtAddrPtr->segPtr, virtAddrPtr->page, ptePtr,
  1036.                  mastSegPtr, others);
  1037.         } else {
  1038.         /*
  1039.          * Copy the page.
  1040.          */
  1041.         virtFrameNum = VmPageAllocate(&virtAddr, VM_CAN_BLOCK);
  1042.         CopyPage(Vm_GetPageFrame(*ptePtr), virtFrameNum);
  1043.         pte = VM_VIRT_RES_BIT | VM_PHYS_RES_BIT | 
  1044.               VM_REFERENCED_BIT | VM_MODIFIED_BIT | virtFrameNum;
  1045.         if (others) {
  1046.             pte |= VM_COW_BIT;
  1047.         }
  1048.         SetPTE(&virtAddr, pte);
  1049.         VmUnlockPage(virtFrameNum);
  1050.         VmUnlockPage(Vm_GetPageFrame(*ptePtr));
  1051.         }
  1052.     } else {
  1053.         /*
  1054.          * The page is on swap space.
  1055.          */
  1056.         (void)VmCopySwapPage(virtAddrPtr->segPtr, 
  1057.                 virtAddrPtr->page, mastSegPtr);
  1058. #ifdef SOSP91
  1059.         if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  1060.         if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  1061.             (proc_RunningProcesses[0]->genFlags &
  1062.             (PROC_FOREIGN | PROC_MIGRATING))) {
  1063.             isForeign = TRUE;
  1064.         }
  1065.         }
  1066.         fs_MoreStats.COWCopySwapPage++;
  1067.         if (isForeign) {
  1068.         fs_MoreStats.COWCopySwapPageM++;
  1069.         }
  1070. #endif SOSP91
  1071.         pte = VM_VIRT_RES_BIT | VM_ON_SWAP_BIT;
  1072.         if (others) {
  1073.         pte |= VM_COW_BIT;
  1074.         }
  1075.         SetPTE(&virtAddr, pte);
  1076.     }
  1077.     if (mastSegPtr->numCOWPages == 0 && mastSegPtr->numCORPages == 0) {
  1078.         mastSegPtr->cowInfoPtr->numSegs--;
  1079.         List_Remove((List_Links *)mastSegPtr);
  1080.         mastSegPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  1081.     }
  1082.     } else {
  1083.     vmStat.quickCOWFaults++;
  1084.     }
  1085.  
  1086.     /*
  1087.      * Change from copy-on-write back to normal if it has not already been
  1088.      * done by some other routine.
  1089.      */
  1090.     if (*ptePtr & VM_COW_BIT) {
  1091.     if (vm_Tracing) {
  1092.         Vm_TracePTEChange    pteChange;
  1093.  
  1094.         pteChange.changeType = VM_TRACE_COW_TO_NORMAL;
  1095.         pteChange.softPTE = TRUE;
  1096.         pteChange.segNum = virtAddrPtr->segPtr->segNum;
  1097.         pteChange.pageNum = virtAddrPtr->page;
  1098.         pteChange.beforePTE = *ptePtr;
  1099.         pteChange.afterPTE = *ptePtr & ~VM_COW_BIT;
  1100.         VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC, sizeof(pteChange),
  1101.                 (Address)&pteChange, TRUE);
  1102.     }
  1103.     ReleaseCOW(ptePtr);
  1104.     }
  1105.     virtAddrPtr->segPtr->numCOWPages--;
  1106.     if (virtAddrPtr->segPtr->numCOWPages < 0) {
  1107.     panic("COW: numCOWPages < 0\n");
  1108.     }
  1109. }
  1110.  
  1111.  
  1112.  
  1113. /*
  1114.  *----------------------------------------------------------------------
  1115.  *
  1116.  * GiveAwayPage --
  1117.  *
  1118.  *    Transfer a page from one segment to another.
  1119.  *
  1120.  * Results:
  1121.  *    None.
  1122.  *
  1123.  * Side effects:
  1124.  *    Source segments page table has the page zapped and the
  1125.  *    destination page table takes over ownership of the page.
  1126.  *
  1127.  *----------------------------------------------------------------------
  1128.  */
  1129. static void
  1130. GiveAwayPage(srcSegPtr, virtPage, srcPTEPtr, destSegPtr, others)
  1131.     register    Vm_Segment    *srcSegPtr;    /* Segment to take page from.*/
  1132.     int                virtPage;    /* Virtual page to give away.*/
  1133.     register    Vm_PTE        *srcPTEPtr;    /* PTE for the segment to take
  1134.                          * the page away from. */
  1135.     register    Vm_Segment    *destSegPtr;    /* Segment to give page to. */
  1136.     Boolean            others;        /* TRUE => other segments that
  1137.                          * are copy-on-write on 
  1138.                          * the destination segment. */
  1139. {
  1140.     Vm_VirtAddr        virtAddr;
  1141.     register    Vm_PTE    *destPTEPtr;
  1142.     unsigned    int    pageFrame;
  1143.     Boolean        referenced;
  1144.     Boolean        modified;
  1145.  
  1146.     LOCK_MONITOR;
  1147.  
  1148.     srcSegPtr->resPages--;
  1149.     destSegPtr->resPages++;
  1150.     virtAddr.segPtr = srcSegPtr;
  1151.     virtAddr.page = virtPage;
  1152.     virtAddr.flags = 0;
  1153.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  1154.     pageFrame = Vm_GetPageFrame(*srcPTEPtr);
  1155.     destPTEPtr = VmGetPTEPtr(destSegPtr, virtPage);
  1156.     *destPTEPtr = *srcPTEPtr & ~VM_COW_BIT;
  1157.     if (vm_Tracing) {
  1158.     Vm_TracePTEChange    pteChange;
  1159.  
  1160.     pteChange.changeType = VM_TRACE_GIVEN_FROM_MASTER;
  1161.     pteChange.softPTE = TRUE;
  1162.     pteChange.segNum = srcSegPtr->segNum;
  1163.     pteChange.pageNum = virtPage;
  1164.     pteChange.beforePTE = *srcPTEPtr;
  1165.     pteChange.afterPTE = 0;
  1166.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC, sizeof(pteChange),
  1167.             (Address)&pteChange, TRUE);
  1168.     }
  1169.     *srcPTEPtr = 0;
  1170.     VmMach_GetRefModBits(&virtAddr, pageFrame, &referenced, &modified);
  1171.     if (referenced) {
  1172.     *destPTEPtr |= VM_REFERENCED_BIT;
  1173.     }
  1174.     if (modified) {
  1175.     *destPTEPtr |= VM_MODIFIED_BIT;
  1176.     }
  1177.     VmMach_PageInvalidate(&virtAddr, pageFrame, FALSE);
  1178.     if (others) {
  1179.     *destPTEPtr |= VM_COW_BIT;
  1180.     }
  1181.     VmPageSwitch(Vm_GetPageFrame(*destPTEPtr), destSegPtr);
  1182.     if (vm_Tracing) {
  1183.     Vm_TracePTEChange    pteChange;
  1184.  
  1185.     pteChange.changeType = VM_TRACE_TAKEN_BY_SLAVE;
  1186.     pteChange.softPTE = TRUE;
  1187.     pteChange.segNum = destSegPtr->segNum;
  1188.     pteChange.pageNum = virtPage;
  1189.     pteChange.beforePTE = 0;
  1190.     pteChange.afterPTE = *destPTEPtr;
  1191.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC, sizeof(pteChange),
  1192.             (Address)&pteChange, TRUE);
  1193.     }
  1194.  
  1195.     UNLOCK_MONITOR;
  1196. }
  1197.  
  1198. /*
  1199.  *----------------------------------------------------------------------
  1200.  *
  1201.  * SetPTE --
  1202.  *
  1203.  *    Set the given pte at the given virtual address.
  1204.  *
  1205.  * Results:
  1206.  *    None.
  1207.  *
  1208.  * Side effects:
  1209.  *    None.
  1210.  *
  1211.  *----------------------------------------------------------------------
  1212.  */
  1213. static void
  1214. SetPTE(virtAddrPtr, pte)
  1215.     Vm_VirtAddr    *virtAddrPtr;
  1216.     Vm_PTE    pte;
  1217. {
  1218.     Vm_PTE    *ptePtr;
  1219.  
  1220.     LOCK_MONITOR;
  1221.  
  1222.     ptePtr = VmGetAddrPTEPtr(virtAddrPtr, virtAddrPtr->page);
  1223.     if (vm_Tracing) {
  1224.     Vm_TracePTEChange    pteChange;
  1225.  
  1226.     pteChange.changeType = VM_TRACE_COW_COR_CHANGE;
  1227.     pteChange.softPTE = TRUE;
  1228.     pteChange.segNum = virtAddrPtr->segPtr->segNum;
  1229.     pteChange.pageNum = virtAddrPtr->page;
  1230.     pteChange.beforePTE = *ptePtr;
  1231.     pteChange.afterPTE = pte;
  1232.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC, sizeof(pteChange),
  1233.             (Address)&pteChange, TRUE);
  1234.     }
  1235.     *ptePtr = pte;
  1236.     if (pte & VM_PHYS_RES_BIT) {
  1237.     virtAddrPtr->segPtr->resPages++;
  1238.     }
  1239.  
  1240.     UNLOCK_MONITOR;
  1241. }
  1242.  
  1243.  
  1244. /*
  1245.  *----------------------------------------------------------------------
  1246.  *
  1247.  * CopyPage --
  1248.  *
  1249.  *    Copy the given page frame to the given destination.
  1250.  *
  1251.  * Results:
  1252.  *    None.
  1253.  *
  1254.  * Side effects:
  1255.  *    None.
  1256.  *
  1257.  *----------------------------------------------------------------------
  1258.  */
  1259. static void
  1260. CopyPage(srcPF, destPF)
  1261.     unsigned    int    srcPF;
  1262.     unsigned    int    destPF;
  1263. {
  1264.     register    Address    srcMappedAddr;
  1265.     register    Address    destMappedAddr;
  1266.  
  1267.     srcMappedAddr = VmMapPage(srcPF);
  1268.     destMappedAddr = VmMapPage(destPF);
  1269.     bcopy(srcMappedAddr, destMappedAddr, vm_PageSize);
  1270.     VmUnmapPage(srcMappedAddr);
  1271.     VmUnmapPage(destMappedAddr);
  1272. }
  1273.  
  1274.  
  1275. /*
  1276.  *----------------------------------------------------------------------
  1277.  *
  1278.  * ReleaseCOW --
  1279.  *
  1280.  *    Make the page no longer copy-on-write.
  1281.  *
  1282.  * Results:
  1283.  *    None.
  1284.  *
  1285.  * Side effects:
  1286.  *    None.
  1287.  *
  1288.  *----------------------------------------------------------------------
  1289.  */
  1290. static void
  1291. ReleaseCOW(ptePtr)
  1292.     Vm_PTE    *ptePtr;
  1293. {
  1294.     LOCK_MONITOR;
  1295.  
  1296.     *ptePtr &= ~VM_COW_BIT;
  1297.  
  1298.     UNLOCK_MONITOR;
  1299. }
  1300.